package se.webbzon.boltzmann.game.object.action;

import java.awt.Color;
import java.util.HashMap;
import java.util.Map;

import se.webbzon.boltzmann.environment.AbstractEnvironment;
import se.webbzon.boltzmann.game.character.AbstractCharacter;
import se.webbzon.boltzmann.game.object.player.AbstractPlayerCharacter;
import se.webbzon.boltzmann.game.sequence.Sequence;
import se.webbzon.boltzmann.game.sequence.SequenceListener;
import se.webbzon.boltzmann.game.sequence.SequenceNode;
import se.webbzon.boltzmann.game.sequence.builder.AbstractSequenceBinding;
import se.webbzon.boltzmann.game.sequence.builder.SequenceBuilder;
import se.webbzon.boltzmann.game.sequence.builder.SequenceBuilderDeflation;
import se.webbzon.oschi01.worldarea.WorldArea;
import se.webbzon.oschi01.worldeditor.DeflatableWorldObject;
import se.webbzon.oschi01.worldeditor.WorldObjectDeflation;
import se.webbzon.oschi01.worldobject.WorldObject;
import se.webbzon.oschi01.worldobject.WorldStaticObject;

public class SequenceAction extends AbstractAction implements DeflatableWorldObject {
	
	// The name of the deflatable world object
	public static final String worldObjectName = "sequenceAction";
	
	// The sequence builder associated with this sequence action
	private final SequenceBuilder builder;
	
	// The sequence node associated with this sequence action 
	// (only available when debug mode is false)
	private SequenceNode sequenceNode;
	
	/*============================================================
	Constructors
	============================================================*/
	
	/** Creates a new sequence action with an empty sequence builder. **/
	public SequenceAction(	AbstractEnvironment env, 
							WorldStaticObject parent,
							Color color,
							boolean frontOnly, double range) {
		this(env,parent,color,frontOnly,range,new SequenceBuilder(env));
	}

	/** Creates a new sequence action. **/
	public SequenceAction(	AbstractEnvironment env,
							WorldStaticObject parent, 
							Color color,
							boolean frontOnly, double range, 
							SequenceBuilder builder) {
		super(0, env, parent, color, frontOnly, range);
		this.builder = builder;
	}
	
	/*============================================================
	Public Methods
	============================================================*/
	
	/** Returns the sequnece builder associated with this sequence action. **/
	public SequenceBuilder getBuilder() {
		return builder;
	}
	
	@Override public void onCreate(WorldArea world) {
		super.onCreate(world);
		if (!getEnvironment().isDebugMode())
			sequenceNode = builder.compile(world);
	}
	
	@Override public void onDestroy(WorldArea world) {
		super.onDestroy(world);
		sequenceNode = null;
	}
	
	@Override public void onActionBegin(WorldStaticObject parent,
										AbstractPlayerCharacter player) {
		player.setFacing(this);
		Object blocker = player.containBlocker();
		
		if (parent instanceof AbstractCharacter) {
			// Face the player is possible
			((AbstractCharacter) parent).setFacing(player);
		}
		
		Map<String,WorldObject> bindings = new HashMap<String,WorldObject>();
		bindings.put(AbstractSequenceBinding.PARENT, parent);
		bindings.put(AbstractSequenceBinding.PLAYER, player);

		Sequence sequence = sequenceNode.getSequence();
		sequence.addListener(new SequenceListenerImpl(player,blocker));
		sequence.begin(	player.getPlayer().getInput(), 
						sequenceNode, 
						bindings);
	}

	@Override public String getName() {
		return worldObjectName;
	}

	@Override public WorldObjectDeflation getDeflation() {
		return new SequenceActionDeflation(0,this,new SequenceBuilderDeflation(builder));
	}
	
	/** An implementation of a sequence listener. **/
	private final class SequenceListenerImpl implements SequenceListener {
		
		// The player associated with this sequence listener
		private final AbstractPlayerCharacter player;
		
		// The player blocker
		private final Object playerBlocker;
		
		/*============================================================
		Constructors
		============================================================*/
		
		public SequenceListenerImpl(AbstractPlayerCharacter player,
									Object playerBlocker) {
			this.player = player;
			this.playerBlocker = playerBlocker;
		}
		
		/*============================================================
		Public Methods
		============================================================*/
		
		@Override public void onSequenceBegin(Sequence sequence) {};

		@Override public void onSequenceEnd(Sequence sequence) {
			sequence.removeListener(this);
			player.releaseBlocker(playerBlocker);
			setActive(true);
		}
		
	}

}
